package com.to8to.autotask.deduction;

import static com.to8to.autotask.util.AutoTaskType.FORFEIT_DEDUCT;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;

import org.elasticsearch.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.to8to.autotask.resulthandler.FailHandler;
import com.to8to.autotask.rpc.CallClient;
import com.to8to.autotask.util.DBUtil;
import com.to8to.autotask.util.Utils;
import com.to8to.es.util.LogUtil;
import com.to8to.thrift.crm.query.TakeOutLatePaymentRequest;

/**
 * ForfeitDeductTask.java
 * 作 者：atom.liu
 * 版 本：v2.0
 * 日 期：2014年12月1日
 * 描 述：自动扣滞纳金任务。每天执行一次。
 *     审核通过装后保7天之内未交保证金的则每天扣50。
 */
public class ForfeitDeductTask implements Runnable
{
    private static final Logger logger = LoggerFactory.getLogger(ForfeitDeductTask.class);

    //这些相关数据暂时写死在代码中，如果前端页面没有提供更改的功能，每次更改都需要修改代码，并重启服务(所以写死在代码和写死在配置文件中差不多一样)。
    /**
     * 不扣滞纳金的城市
     */
    private static CopyOnWriteArrayList<Integer> notCostCity = Lists.newCopyOnWriteArrayList();
    //Arrays.asList(1130, 1121);

    /**
     * 新增的不扣滞纳金的城市 
     * 2015-01-21 落地城市列表调用服务获取，不再写死  modify by atom.liu
     */
    private static CopyOnWriteArrayList<Integer> newNotCostCity = Lists.newCopyOnWriteArrayList();
    //Arrays.asList(1181, 1672, 2827, 1103, 591, 2929, 1196, 1695, 2920, 1547, 2619);

    /**
     * 在新增的不扣滞纳金的城市中（newNotCostCity），依然需要扣滞纳金的公司id
     */
    private static CopyOnWriteArrayList<Integer> needCostUidAtNewNotCostCity = Lists.newCopyOnWriteArrayList();
    //Arrays.asList(268581, 745458, 726523, 519907, 351016, 314974, 286429, 270093, 268734, 158090, 236275, 293487, 295975, 304611, 851480, 418599, 472333, 846830, 847956, 539354, 554978, 609927, 639309, 734584, 780321, 810545, 810654, 818768, 831186, 857244, 612638, 289814, 335498, 378965, 381934, 491382, 520575, 593221, 648063, 726621, 763728, 773249, 789808, 804411, 817717, 820918, 835361, 848736, 852939, 853964, 873520, 877478, 893287, 894830, 928575, 935988, 952317, 969413, 973803, 208706, 280276, 296801, 306963, 309603, 334981, 340200, 341565, 352267, 362696, 372858, 376493, 400004, 621319, 627084, 648988, 668335, 714673, 800564, 879394, 911954, 922948, 873809, 984074, 983996, 382079, 385139, 1108044, 364613, 446834, 1187686, 479804, 1184070, 1173684, 635505, 635821, 686004, 724109, 742145, 808675, 817770, 835099, 875031, 968782, 971041, 1018182, 1021038, 1038519, 1082743, 300037, 1180333, 313228, 361909, 372371, 1193093, 1193100, 384991, 399603, 1127874, 1193503, 629306, 790813, 808715, 810212, 872574, 872717, 882883, 884178, 888885, 893027, 897813, 911484, 919497, 935493, 935533, 949521, 964805, 966407, 973291, 1016164, 1071219, 1197281, 990048, 1193510, 228560, 291094, 337798, 347795, 364999, 365221, 378997, 380695, 386034, 387089, 392448, 397588, 410789, 412245, 474512, 499486, 543465, 548131, 572256, 623582, 630505, 633139, 653723, 666271, 728246, 730523, 747161, 759837, 767369, 770130, 777194, 785131, 785143, 786869, 819368, 838502, 919657, 958171, 962140, 966150, 969240, 970406, 973286, 985565, 1005070, 1019341, 1019685, 1021153, 1042972, 1044971, 1055433, 1076341, 1095219, 1180050, 1182209, 1182684, 1192800, 1203938, 1209810, 1210007, 1214801, 1229448, 1235067, 1239902, 1243273, 1248659, 1256445, 1260357, 242461, 253510, 322178, 378398, 576947, 935254, 937912, 970500, 981534, 1060618, 1128378, 1182360, 1227468, 1235536, 1238209, 1268048, 1375915);

    /**
     * 不扣滞纳金的公司id
     */
    public static CopyOnWriteArrayList<Integer> notCostUid = Lists.newCopyOnWriteArrayList();
    //Arrays.asList(396104, 301145, 420791, 432513);

    /**
     * 不扣滞纳金的项目id
     */
    private static CopyOnWriteArrayList<Integer> notCostYid = Lists.newCopyOnWriteArrayList();
    //Arrays.asList(101387, 119097, 142734, 768698);

    /**
     * SQL: 查询出符合条件的中标记录
     * chuli=2：审核通过 
     * iscostbzj=0：未交保证金 
     * zxbyh = 0：装后保
     * cputtime > 1353600000: 从2012-11-23开始执行
     * cancost >　0:公司可用余额大于0
     * (is_gz = 0) or (z.is_gz = 1 & z.c_price < 300000)：家装 或者 小于30W的公装
     * cputtime < 7天：提交中标时间为7天之前
     * f.fz_city not in ?：部分城市不扣
     * z.uid not in ?：部分公司不扣
     * z.yid not in ?：部分项目不扣
     */
    private static final String ZB_SQL =
        "select * from to8to_jj_smt_zb as z left join to8to_fcom as f on z.uid = f.id where f.fz_city not in (%s) and z.uid not in (%s) and z.yid not in (%s) and z.chuli = 2 and z.iscostbzj = 0 and z.zxbyh = 0 and z.cputtime < ? and z.cputtime > 1353600000 and (z.is_gz = 0 or (z.is_gz = 1 and z.c_price < 300000)) and z.yid > 0 and f.cancost > 0 and z.jg_time = 0";

    @Override
    public void run()
    {
        logger.info("自动扣滞纳金任务开始 ...");

        Connection connect = null;

        try
        {
            connect = DBUtil.getConnection();

            //获得符合要求的记录，并返回zid uid
            List<TakeOutLatePaymentRequest> reqs = getSatisfyConditionRecord(connect);
            if (Utils.isNullOrEmpty(reqs))
            {
                logger.info("本次任务没有要扣滞纳金的公司");
                return;
            }

            if (DBUtil.execTaskCountsAtToday(connect, FORFEIT_DEDUCT) != 0)
                return;

            recordLog(reqs, connect);
            CallClient.takeOutLatePaymentFromCompany(reqs);
            logger.info("自动扣滞纳金任务结束 ...");
        }
        catch (Throwable e)
        {
            logger.error("自动扣滞纳金任务出现异常！{} \n {}", e, LogUtil.logStackTrace(e));
            if (e instanceof SQLException)
                FailHandler.handler(ForfeitDeductTask.class);
        }
        finally
        {
            DBUtil.releaseSource(null, null, connect);
        }
    }

    /**
     * 初始化配置信息 
     */
    public static void initConfig(Map<String, List<String>> map)
    {
        convertString2Integer(map.get("not_cost_uid"), notCostUid);
        convertString2Integer(map.get("not_cost_yid"), notCostYid);
        convertString2Integer(map.get("not_cost_city"), notCostCity);
        convertString2Integer(map.get("new_not_cost_city"), newNotCostCity);
        convertString2Integer(map.get("need_cost_uid"), needCostUidAtNewNotCostCity);
        StringBuilder sb = new StringBuilder();

        sb.append("不需要扣滞纳金的城市：" + notCostCity);
        sb.append("\r\n不需要扣滞纳金的公司:" + notCostUid);
        sb.append("\r\n不需要扣滞纳金的项目:" + notCostYid);
        sb.append("\r\n新增的不需要扣滞纳金的城市:" + newNotCostCity);
        sb.append("\r\n新增不需要扣滞纳金城市中依然需要扣滞纳金的公司:" + needCostUidAtNewNotCostCity);

        logger.info(sb.toString());
    }

    private static void convertString2Integer(List<String> strList, CopyOnWriteArrayList<Integer> intList)
    {
        intList.clear();
        if (Utils.isNullOrEmpty(strList))
            return;
        for (String i : strList)
        {
            try
            {
                intList.add(Integer.parseInt(i));
            }
            catch (NumberFormatException e)
            {
                logger.error("parseInt失败！{} \n {}", e, LogUtil.logStackTrace(e));
            }
        }
    }

    /**
     * 自动任务信息入库
     */
    private void recordLog(List<TakeOutLatePaymentRequest> reqs, Connection connect)
    {
        List<String> sqls = Lists.newArrayList();
        sqls.add("本次要调用自动扣滞纳金的信息：");
        for (TakeOutLatePaymentRequest req : reqs)
        {
            StringBuilder sb = new StringBuilder();
            sb.append("uid : ").append(req.getCid()).append(", zid :").append(req.getZid());
            sqls.add(sb.toString());
        }

        DBUtil.recordAutoTaskLog(connect, FORFEIT_DEDUCT, sqls, true);
    }

    /**
     * 获得符合条件的要扣滞纳金的公司id集合
     */
    private List<TakeOutLatePaymentRequest> getSatisfyConditionRecord(Connection connect) throws SQLException
    {
        String cityStr = Utils.collect2Str(notCostCity);
        String uidStr = Utils.collect2Str(notCostUid);
        String yidStr = Utils.collect2Str(notCostYid);
        int cputtime = ((int) (System.currentTimeMillis() / 1000)) - 7 * 24 * 60 * 60;
        PreparedStatement stat = connect.prepareStatement(String.format(ZB_SQL, cityStr, uidStr, yidStr));
        stat.setInt(1, cputtime);
        ResultSet result = stat.executeQuery();
        List<TakeOutLatePaymentRequest> reqs = Lists.newArrayList();
        while (result.next())
        {
            int fz_city = result.getInt("fz_city");
            int uid = result.getInt("uid");
            if (!newNotCostCity.contains(fz_city) || needCostUidAtNewNotCostCity.contains(uid))
            {
                TakeOutLatePaymentRequest req = new TakeOutLatePaymentRequest();
                req.setCid(uid);
                req.setZid(result.getInt("zid"));
                reqs.add(req);
            }
        }

        DBUtil.releaseSource(result, stat, null);

        return reqs;
    }

    /**
     * 是否需要扣除滞纳金
     * @param uid 公司id
     * @param yid 项目id
     * @param fz_city 公司所在城市
     * @return 0：不需要扣除；1：需要扣; -1:服务出错; -2：没有查到对应信息
     */
    public static int isCostForfeit(int uid, int yid, int fz_city)
    {
        if (notCostUid.contains(uid) || notCostCity.contains(fz_city) || notCostYid.contains(yid))
            return 0;

        Connection connect = null;
        PreparedStatement stat = null;
        ResultSet result = null;
        try
        {
            connect = DBUtil.getConnection();

            String sql = "select z.c_price,z.is_gz from to8to_jj_smt_zb as z left join to8to_fcom as f on z.uid = f.id where z.yid = ? and z.uid = ?";
            stat = connect.prepareStatement(sql);
            stat.setInt(1, yid);
            stat.setInt(2, uid);
            result = stat.executeQuery();
            while (result.next())
            {
                int price = result.getInt("z.c_price");
                int is_gz = result.getInt("z.is_gz");

                if (is_gz == 1 && price >= 300000)
                    return 0;
                //新加入的不扣费城市，和不扣费城市中需要扣费的公司  这两个判断条件，需要放到公装、家装判断之后；而且这两个顺序不能反
                if (needCostUidAtNewNotCostCity.contains(uid))
                    return 1;
                if (newNotCostCity.contains(fz_city))
                    return 0;
                return 1;
            }
            return -2;
        }
        catch (Exception e)
        {
            logger.error("是否需要扣除滞纳金服务异常！{} \n {}", e, LogUtil.logStackTrace(e));
            return -1;
        }
        finally
        {
            DBUtil.releaseSource(result, stat, connect);
        }
    }
}
